import numpy as np
import pandas as pd
from tqdm import tqdm
import matplotlib.pyplot as plt
import statsmodels.api as sm
from collections import Counter
import seaborn as sns

class SimpleAnalysis(object):

    def __init__(self, factor, ret, freq):
        
        self.factor = factor
        self.ret = ret
        self.freq = freq

    def IC_ana(self,type):
        IC = self.factor.corrwith(self.ret, axis = 1, method = type).dropna() 
        return IC

    def ana_IC_indicator(self, type='spearman', id='factor'):
    # 计算整体IC指标
        IC_Series = self.IC_ana(type)
        IC_Series.name = type
        
        # 计算统计指标
        ic_mean = IC_Series.mean()
        ic_std = IC_Series.std()
        ic_ir = ic_mean / ic_std
        ic_indicators = pd.Series({'ic_mean': ic_mean, 'ic_std': ic_std, 'ic_ir': ic_ir})
        ic_indicators.name = type
        display(ic_indicators)

        # 按年度计算IC指标
        IC_Series.index = pd.to_datetime(IC_Series.index)
        year_mean = IC_Series.groupby(IC_Series.index.year).mean()
        year_std = IC_Series.groupby(IC_Series.index.year).std()
        year_ir = year_mean / year_std

        # 计算累积IC
        ic_cum = IC_Series.cumsum()

        # 创建双轴图表
        fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(18, 6), gridspec_kw={'width_ratios': [2, 1]})
        
        # 左图：IC时序和累积IC
        ax1.plot(IC_Series, label=f'Monthly IC (Mean={ic_mean:.2f})', color='#1f77b4', linewidth=1.5)
        ax1.set_ylabel('IC Value', fontsize=12)
        ax1.grid(True, linestyle='--', alpha=0.6)
        
        ax1_cum = ax1.twinx()
        ax1_cum.plot(ic_cum, label='Cumulative IC', color='#ff7f0e', linewidth=1.5, alpha=0.7)
        ax1_cum.set_ylabel('Cumulative IC', fontsize=12)
        
        ax1.set_title(f'{id} {type.upper()} IC Series', fontsize=14)
        ax1.legend(loc='upper left')
        ax1_cum.legend(loc='upper right')
        plt.setp(ax1.get_xticklabels(), rotation=45, ha='right')

        # 右图：年度IC条形图
        colors = ['#4c72b0' if x > 0 else '#c44e52' for x in year_mean.values]
        ax2.bar(year_mean.index.astype(str), year_mean.values, color=colors, alpha=0.7)
        
        # 添加数值标签
        for i, (mean, ir) in enumerate(zip(year_mean, year_ir)):
            ax2.text(i, mean/2 if mean > 0 else mean-0.01, 
                    f'{mean:.2f}\nIR={ir:.2f}', 
                    ha='center', va='center', color='white' if mean > 0 else 'black')
        
        ax2.set_title('Annual IC Performance', fontsize=14)
        ax2.grid(True, axis='y', linestyle=':', alpha=0.6)
        ax2.axhline(0, color='black', linewidth=0.8)
        plt.setp(ax2.get_xticklabels(), rotation=45)

        plt.tight_layout()
        plt.show()
        
        return year_mean, year_ir, ic_indicators



    def cal_quantile_daily(self,date):
        daily_factor = self.factor.loc[date]
        daily_ret = self.ret.loc[date] 
        iCodes = daily_factor.dropna().index.intersection(daily_ret.dropna().index)
        factor_values = daily_factor.reindex(iCodes)
        ret_values = daily_ret.reindex(iCodes)
        bins = pd.qcut(factor_values, 10 , labels=False) +1 
        quantiles = {}
        for bin in bins.unique() :
            quantiles[bin] = ret_values[bins == bin].mean()
        quantiles = pd.Series(quantiles)
        return quantiles.sort_index()


    def cal_quantile_ret(self):
        return_Series = {}
        common_date = self.factor.dropna(axis = 0, how = 'all').index.intersection(self.ret.dropna(axis = 0, how = 'all').index)
        for date in tqdm(common_date):
            return_Series[date] = self.cal_quantile_daily(date)
        return_Series = pd.DataFrame(return_Series)
        return return_Series.T
        

    def quantile_ana(self, ret_portfolio):

        if self.freq[0] == 'D':
            indicater_id = ['总收益 (%)','日均收益 (%)', '年化收益 (%)','年化波动率 (%)','夏普比率','卡玛比率','最大回撤 (%)','最长回撤']
            # indicator = []
            all_return = ret_portfolio.iloc[-1] - 1
            year_return = (ret_portfolio.iloc[-1]) ** (252 / ret_portfolio.shape[0]) -1
            day_vol = (ret_portfolio).pct_change().dropna().std()
            year_vol = day_vol * np.sqrt(252)
        elif self.freq[0] == 'M':
            indicater_id = ['总收益 (%)','月均收益 (%)', '年化收益 (%)','年化波动率 (%)','夏普比率','卡玛比率','最大回撤 (%)','最长回撤']
            all_return = ret_portfolio.iloc[-1] - 1
            year_return = (ret_portfolio.iloc[-1]) ** (12 / ret_portfolio.shape[0]) -1
            day_vol = (ret_portfolio).pct_change().dropna().std()
            year_vol = day_vol * np.sqrt(12)
        else:
            raise ValueError('please input D or M')

        #日均收益
        # meanReturn = dayReturn.mean()/period*100.0  #平均
        meanReturn = (ret_portfolio.iloc[-1] ** (1./ret_portfolio.shape[0]) - 1) 


        sharpe = year_return / year_vol if year_vol != 0 else 0

        max_cum = np.maximum.accumulate(ret_portfolio)
        drawback = 1 - ((ret_portfolio)) / max_cum
        max_drawback = np.max(drawback)

        carlmar = year_return / max_drawback

        longest_drawback = Counter(max_cum).most_common()[0][1]
        indicator = [all_return *100,meanReturn *100,  year_return *100, year_vol *100, sharpe, carlmar, max_drawback *100, longest_drawback]
        return (pd.Series(indicator, index = indicater_id))

    def cal_quantile_all_indicators_without_turnover(self, id):
        # 计算每日各分层收益
        factor_ret = self.cal_quantile_ret()
        factor_ret_mean = factor_ret.mean()

        # 强制白色背景样式
        plt.style.use('default')
        plt.rcParams['figure.facecolor'] = 'white'
        plt.rcParams['axes.facecolor'] = 'white'
        
        #######################################
        # 1. 日收益柱状图（白色背景+蓝色系）
        #######################################
        plt.figure(figsize=(12, 6), facecolor='white')
        
        # 蓝色渐变色系 (从浅蓝到深蓝)
        cmap = plt.cm.get_cmap('Blues', len(factor_ret_mean)+3)
        colors = [cmap(i+2) for i in range(len(factor_ret_mean))]  # 跳过最浅的两档
        
        bars = plt.bar(factor_ret_mean.index, factor_ret_mean.values, 
                    color=colors, edgecolor='white', linewidth=1.2)
        
        # 添加数值标签（深蓝色文字）
        for bar in bars:
            height = bar.get_height()
            plt.text(bar.get_x() + bar.get_width()/2., height,
                    f'{height:.4f}',
                    ha='center', va='bottom', fontsize=10, color='#0B3D91')

        # 设置白色背景元素
        ax = plt.gca()
        ax.set_facecolor('white')
        plt.grid(axis='y', linestyle='--', alpha=0.6, color='lightgray')
        plt.title(f'{id} - Daily Mean Return by Quantile', fontsize=14, pad=20, color='#0B3D91')
        plt.xlabel('Quantile', fontsize=12, labelpad=10, color='#0B3D91')
        plt.xticks(rotation=45, ha='right')
        plt.ylabel('Mean Return', fontsize=12, labelpad=10, color='#0B3D91')
        
        # 调整坐标轴颜色
        ax.spines['bottom'].set_color('#3A7CB8')
        ax.spines['left'].set_color('#3A7CB8')
        ax.tick_params(axis='x', colors='#3A7CB8')
        ax.tick_params(axis='y', colors='#3A7CB8')
        
        plt.tight_layout()
        plt.show()

        #######################################
        # 2. 计算累计收益指标（白色背景表格）
        #######################################
        factor_cum_ret = (factor_ret+1).cumprod()
        factor_cum_ret = factor_cum_ret.dropna(how='all')
        
        factor_quantiles_ana_result = pd.concat([
            self.quantile_ana(factor_cum_ret[x]) for x in factor_cum_ret.columns], axis=1)
        factor_quantiles_ana_result.columns = list(factor_quantiles_ana_result.columns[:10] + 1)
        
        # 白色背景+蓝色文字表格
        try:
            styled_result = (factor_quantiles_ana_result.style
                            .background_gradient(cmap='Blues', axis=1, vmin=0)
                            .format("{:.4f}")
                            .set_caption(f"Performance Metrics - {id}")
                            .set_properties(**{
                                'color': '#0B3D91',
                                'background-color': 'white'
                            }))
            display(styled_result)
        except:
            display(factor_quantiles_ana_result)
        

        #######################################
        # 3. 累计收益曲线图（纯白背景+蓝色系）
        #######################################
        plt.figure(figsize=(18, 8), facecolor='white')
        
        # 精心调校的蓝色系（NASA风格蓝）
        blue_palette = [
            '#87CEEB',  # 浅天蓝
            '#5D8AA8',  # 空军蓝
            '#1E90FF',  # 道奇蓝
            '#0066CC',  # 深天蓝
            '#003366',  # 午夜蓝
            '#002366',  # 皇家蓝
            '#0B3D91',  # NASA蓝
            '#1560BD',  # 牛仔蓝
            '#1A4F8B',  # 东方蓝
            '#1C39BB'   # 波斯蓝
        ]
        
        # 绘制每条曲线
        for i, col in enumerate(factor_cum_ret.columns):
            plt.plot(factor_cum_ret.index, factor_cum_ret[col], 
                    label=f'Quantile {col}', 
                    color=blue_palette[i%len(blue_palette)],
                    linewidth=2.5,
                    alpha=0.9)
        
        # 修改 plt.annotate 部分代码（累计收益图中）
        for i, col in enumerate(factor_cum_ret.columns):
            last_val = factor_cum_ret[col].iloc[-1]
            plt.annotate(f'{last_val:.2f}', 
                        xy=(factor_cum_ret.index[-1], last_val),
                        xytext=(10, 0), textcoords='offset points',
                        va='center', fontsize=10, color='#0B3D91',
                        bbox=dict(boxstyle='round,pad=0.3', 
                                fc=(1, 1, 1, 0.8),  # 改为元组格式的RGBA
                                ec='#3A7CB8', 
                                lw=1))


        # 设置纯白背景
        ax = plt.gca()
        ax.set_facecolor('white')
        plt.grid(True, linestyle='--', alpha=0.5, color='lightgray')
        
        # 标题和标签（NASA蓝）
        plt.title(f'{id} - Cumulative Return by Quantile', fontsize=14, pad=20, color='#0B3D91')
        plt.xlabel('Date', fontsize=12, labelpad=10, color='#0B3D91')
        plt.xticks(factor_cum_ret.index[::60], rotation=45, ha='right')
        plt.ylabel('Cumulative Return', fontsize=12, labelpad=10, color='#0B3D91')
        
        # 图例设置（白色背景+蓝色边框）
        legend = plt.legend(bbox_to_anchor=(1.02, 1), loc='upper left', 
                        borderaxespad=0., framealpha=1,
                        facecolor='white', edgecolor='#3A7CB8',
                        title='Quantiles', title_fontsize=11)
        plt.setp(legend.get_title(), color='#0B3D91')
        for text in legend.get_texts():
            text.set_color('#0B3D91')
        
        # 坐标轴样式
        ax.spines['bottom'].set_color('#3A7CB8')
        ax.spines['left'].set_color('#3A7CB8')
        ax.spines['top'].set_visible(False)
        ax.spines['right'].set_visible(False)
        ax.tick_params(axis='x', colors='#3A7CB8')
        ax.tick_params(axis='y', colors='#3A7CB8')
        
        plt.tight_layout()
        plt.show()

    # 计算换手率
    def cal_turnover(self,num):
        bins = self.factor.apply(lambda x: pd.qcut(x, 10, labels= False, duplicates = 'drop'), axis = 1) +1
        fac_num = self.factor[bins == num]
        # commonfactor = up_factor[up_factor.notna() & ret.notna()]
        fac_num_shift = fac_num.shift(1)
        same_stocks = fac_num[fac_num_shift.notna()].count(axis = 1)
        stock_before = fac_num_shift.count(axis = 1)
        tr = 1 - same_stocks / stock_before
        tr.name = num
        return tr.fillna(0)
        

    def cal_quantile_all_indicators_with_turnover(self, id):
        # 设置白色背景样式
        plt.style.use('default')
        plt.rcParams['figure.facecolor'] = 'white'
        plt.rcParams['axes.facecolor'] = 'white'
        
        factor_ret = self.cal_quantile_ret()
        turnovre_ratio = pd.concat([self.cal_turnover(num) for num in range(1,11)], axis=1)

        #######################################
        # 1. 换手率曲线图（蓝色系）
        #######################################
        plt.figure(figsize=(18, 6), facecolor='white')
        
        # 使用NASA蓝色系
        line_colors = ['#1E90FF', '#0B3D91']  # 浅蓝和深蓝
        
        for i, col in enumerate([1, 10]):
            plt.plot(turnovre_ratio.index, turnovre_ratio[col], 
                    color=line_colors[i],
                    linewidth=2,
                    label=f'Quantile {col}')

        ax = plt.gca()
        ax.set_facecolor('white')
        plt.grid(True, linestyle='--', alpha=0.5, color='lightgray')
        plt.title(f'{id} - Turnover Ratio (Quantile 1 & 10)', fontsize=14, pad=20, color='#0B3D91')
        plt.xlabel('Date', fontsize=12, labelpad=10, color='#0B3D91')
        plt.xticks(turnovre_ratio.index[::60], rotation=45, ha='right')
        plt.ylabel('Turnover Ratio', fontsize=12, labelpad=10, color='#0B3D91')
        
        # 添加最后值标注
        for i, col in enumerate([1, 10]):
            last_val = turnovre_ratio[col].iloc[-1]
            plt.annotate(f'{last_val:.2%}', 
                        xy=(turnovre_ratio.index[-1], last_val),
                        xytext=(10, 0), textcoords='offset points',
                        va='center', fontsize=10, color=line_colors[i],
                        bbox=dict(boxstyle='round,pad=0.3', 
                                fc=(1, 1, 1, 0.8),
                                ec=line_colors[i],
                                lw=1))
        
        legend = plt.legend(bbox_to_anchor=(1.02, 1), loc='upper left',
                        facecolor='white', edgecolor='#3A7CB8',
                        title='Quantiles', title_fontsize=11)
        plt.setp(legend.get_title(), color='#0B3D91')
        plt.tight_layout()
        plt.show()

        #######################################
        # 2. 考虑费用后的收益柱状图
        #######################################
        # 计算交易费用
        trade_fee = 2 * turnovre_ratio * 0.0003 + 0.0005 * turnovre_ratio
        factor_ret_fee = factor_ret - trade_fee
        factor_ret_fee_mean = factor_ret_fee.mean()

        plt.figure(figsize=(12, 6), facecolor='white')
        
        # 蓝色渐变色柱状图
        cmap = plt.cm.get_cmap('Blues', len(factor_ret_fee_mean)+3)
        colors = [cmap(i+2) for i in range(len(factor_ret_fee_mean))]
        
        bars = plt.bar(factor_ret_fee_mean.index, factor_ret_fee_mean.values,
                    color=colors, edgecolor='white', linewidth=1.2)
        
        # 添加数值标签
        for bar in bars:
            height = bar.get_height()
            plt.text(bar.get_x() + bar.get_width()/2., height,
                    f'{height:.4f}',
                    ha='center', va='bottom', fontsize=10, color='#0B3D91')

        ax = plt.gca()
        ax.set_facecolor('white')
        plt.grid(axis='y', linestyle='--', alpha=0.6, color='lightgray')
        plt.title(f'{id} - Mean Return After Fees', fontsize=14, pad=20, color='#0B3D91')
        plt.xlabel('Quantile', fontsize=12, labelpad=10, color='#0B3D91')
        plt.xticks(rotation=45)
        plt.ylabel('Mean Return', fontsize=12, labelpad=10, color='#0B3D91')
        plt.tight_layout()
        plt.show()

        #######################################
        # 3. 累计收益曲线及分析
        #######################################
        factor_cum_ret = (factor_ret_fee+1).cumprod()
        factor_cum_ret = factor_cum_ret.dropna(how='all')
        
        # 性能指标分析
        factor_quantiles_ana_result = pd.concat([
            self.quantile_ana(factor_cum_ret[x]) for x in factor_cum_ret.columns], axis=1)
        factor_quantiles_ana_result.columns = factor_quantiles_ana_result.columns[:10] + 1
        
        # 美化表格输出
        try:
            styled_result = (factor_quantiles_ana_result.style
                            .background_gradient(cmap='Blues', axis=1, vmin=0)
                            .format("{:.4f}")
                            .set_caption(f"Performance Metrics (After Fees) - {id}"))
            display(styled_result)
        except:
            display(factor_quantiles_ana_result)
        
        #######################################
        # 4. 累计收益曲线图（蓝色系）
        #######################################
        plt.figure(figsize=(18, 8), facecolor='white')
        
        # 蓝色调色板（10种蓝色）
        blue_palette = [
            '#87CEEB', '#5D8AA8', '#1E90FF', '#0066CC', 
            '#003366', '#002366', '#0B3D91', '#1560BD',
            '#1A4F8B', '#1C39BB'
        ]
        
        for i, col in enumerate(factor_cum_ret.columns):
            plt.plot(factor_cum_ret.index, factor_cum_ret[col], 
                    color=blue_palette[i],
                    linewidth=2.5,
                    alpha=0.9,
                    label=f'Quantile {col}')
        
        # 添加最后值标注
        for i, col in enumerate(factor_cum_ret.columns):
            last_val = factor_cum_ret[col].iloc[-1]
            plt.annotate(f'{last_val:.2f}', 
                        xy=(factor_cum_ret.index[-1], last_val),
                        xytext=(10, 0), textcoords='offset points',
                        va='center', fontsize=10, color=blue_palette[i],
                        bbox=dict(boxstyle='round,pad=0.3', 
                                fc=(1, 1, 1, 0.8),
                                ec=blue_palette[i],
                                lw=1))

        ax = plt.gca()
        ax.set_facecolor('white')
        plt.grid(True, linestyle='--', alpha=0.5, color='lightgray')
        plt.title(f'{id} - Cumulative Return After Fees', fontsize=14, pad=20, color='#0B3D91')
        plt.xlabel('Date', fontsize=12, labelpad=10, color='#0B3D91')
        plt.xticks(factor_cum_ret.index[::60], rotation=45, ha='right')
        plt.ylabel('Cumulative Return', fontsize=12, labelpad=10, color='#0B3D91')
        
        legend = plt.legend(bbox_to_anchor=(1.02, 1), loc='upper left',
                        facecolor='white', edgecolor='#3A7CB8',
                        title='Quantiles', title_fontsize=11)
        plt.setp(legend.get_title(), color='#0B3D91')
        plt.tight_layout()
        plt.show()

        return turnovre_ratio.mean()
